﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kooboo.Commerce.Contexts.Products;
using Kooboo.Commerce.Contexts.Categories;
using Kooboo.Commerce.Contexts.Brands;
using Kooboo.Commerce.Contexts.ShopSettings;

namespace Kooboo.Commerce.Services
{
    public class ProductService : ServiceBase
    {
        public IEnumerable<SaleProduct> GetLatestProducts(int top)
        {
            return this.Actor.QueryProducts()
                .SelectMany(i => i.SaleItems)
                .OrderByDescending(i => i.Id)
                .Select(i => new SaleProduct
                {
                    ProductId = i.Product.Id,
                    Name = i.Product.Name,
                    Price = i.RetailPrice,
                    Thumbnail = i.Product.ProductImages.OrderByDescending(m => m.CoverImage).Select(m => m.Name).FirstOrDefault()
                })
                .Take(top)
                .AsEnumerable();
        }

        public IEnumerable<SaleProduct> GetProductsByCategoryId(int id, ProductSortType sort = ProductSortType.NameByAsc, int? pageIndex = null, int? pageSize = null)
        {
            var items = this.Actor.QueryCategories()
                .Where(i => i.Id == id)
                .FirstOrDefault()
                .Products
                .SelectMany(i => i.SaleItems)
                .Select(i => new SaleProduct
                {
                    ProductId = i.Product.Id,
                    Name = i.Product.Name,
                    Price = i.RetailPrice,
                    Thumbnail = i.Product.ProductImages.OrderByDescending(m=>m.CoverImage).Select(m => m.Name).FirstOrDefault()
                })
                .OrderBy(i => i.ProductId);

            switch (sort)
            {
                case ProductSortType.NameByAsc:
                    items = items.OrderBy(i => i.Name);
                    break;
                case ProductSortType.NameByDesc:
                    items = items.OrderByDescending(i => i.Name);
                    break;
                case ProductSortType.PriceByAsc:
                    items = items.OrderBy(i => i.Price);
                    break;
                case ProductSortType.PriceByDesc:
                    items = items.OrderByDescending(i => i.Price);
                    break;
            }

            if (pageIndex.HasValue && pageSize.HasValue)
            {
                if (pageIndex.Value > 0)
                {
                    return items
                        .Skip(pageSize.Value * (pageIndex.Value - 1))
                        .Take(pageSize.Value)
                        .AsEnumerable();
                }
            }

            return items.AsEnumerable();

        }

        public IEnumerable<SaleProduct> GetProductsByBrandId(int id, ProductSortType sort = ProductSortType.NameByAsc, int? pageIndex = null, int? pageSize = null)
        {
            var items = this.Actor.QueryBrands()
                .Where(i => i.Id == id)
                .FirstOrDefault()
                .Products
                .SelectMany(i => i.SaleItems)
                .Select(i => new SaleProduct
                {
                    ProductId = i.Product.Id,
                    Name = i.Product.Name,
                    Price = i.RetailPrice,
                    Thumbnail = i.Product.ProductImages.OrderByDescending(m => m.CoverImage).Select(m => m.Name).FirstOrDefault()
                })
                .OrderBy(i => i.ProductId);

            switch (sort)
            {
                case ProductSortType.NameByAsc:
                    items = items.OrderBy(i => i.Name);
                    break;
                case ProductSortType.NameByDesc:
                    items = items.OrderByDescending(i => i.Name);
                    break;
                case ProductSortType.PriceByAsc:
                    items = items.OrderBy(i => i.Price);
                    break;
                case ProductSortType.PriceByDesc:
                    items = items.OrderByDescending(i => i.Price);
                    break;
            }

            if (pageIndex.HasValue && pageSize.HasValue)
            {
                if (pageIndex.Value > 0)
                {
                    return items
                        .Skip(pageSize.Value * (pageIndex.Value - 1))
                        .Take(pageSize.Value)
                        .AsEnumerable();
                }
            }

            return items.AsEnumerable();

        }

        public Product GetProductById(int id)
        {
            Int32 defaultDeliveryDays = Actor.GetShopSettings().DefaultDeliveryDays;

            return this.Actor.QueryProducts()
                .Where(i => i.Id == id)
                .Select(i => new Product
                {
                    Id = i.Id,
                    Name = i.Name,
                    Description = i.Description,
                    SkuAlias = i.ProductType.SkuAlias ?? "SKU",
                    BrandName = i.Brand.Name,
                    BrandId = i.Brand.Id,
                    Images = i.ProductImages.Select(m => m.DetailUrl(AppEnvironment.Folders.Product)).ToArray(),
                    Sales = i.SaleItems.Select(m => new SaleInfo
                    {
                        Id = m.Id,
                        Name = string.Join("+", m.ProductVariations.Select(n => n.Value).ToArray()),
                        Stock = m.Stock,
                        Price = m.RetailPrice,
                        Sku = m.SKU,
                        Items = m.ProductVariations.Select(n => new Item { Name = n.Variation.Name, Value = n.Value }).ToArray(),
                        DeliveryDays = m.DeliveryDays == 0 ? defaultDeliveryDays : m.DeliveryDays
                    })
                    .ToArray(),
                    Specification = i.ProductCustomFields.Select(m => new SpecInfo
                    {
                        Name = m.CustomField.Name,
                        Value = m.Value
                    })
                    .ToArray(),
                    Questions = i.ProductQuestions.Select(m => new QuestionInfo
                    {
                        QuestionBy = m.QuestionBy,
                        Question = m.Question,
                        Answer = m.Answer,
                        AnsweredBy = m.AnsweredBy,
                        AnswerDate = m.AnswerDate,
                        QuestionDate = m.QuestionDate,
                        QuestionEmail = m.QuestionEmail,
                        Id = m.Id
                    })
                    .ToArray(),
                    Reviews = i.ProductReviews.Select(m => new ReviewInfo
                    {
                        Id = m.Id,
                        CreateDate = m.CreateDate,
                        Customer = m.Customer,
                        IsPublished = m.IsPublished,
                        Rate = m.Rate,
                        Remark = m.Remark,
                        Order = m.Order
                    })
                    .ToArray()
                })
                .FirstOrDefault();
        }

        public dynamic GetProductQuestions(Int32 productId, Int32? pageIndex = null, int? pageSize = null)
        {
            pageIndex = pageIndex ?? 1;
            pageSize = pageSize ?? 20;

            var product = GetProductById(productId);
            if (product != null)
            {
                var questions = product.Questions.OrderByDescending(q => q.QuestionDate).Select(q => new
                    {
                        Question = q.Question,
                        QuestionDate = q.QuestionDate.Value.ToString("F"),
                        QuestionBy = q.QuestionBy,
                        AnswerBy = q.AnsweredBy,
                        Answer = q.Answer,
                        AnswerDate = q.AnswerDate.HasValue ? q.AnswerDate.Value.ToString("F") : ""
                    });
                return new
                {
                    Items = questions.Skip(pageSize.Value * (pageIndex.Value - 1)).Take(pageSize.Value).AsEnumerable(),
                    Total = questions.Count(),
                    PageSize = pageSize.Value
                };
            }
            else
            {
                return Enumerable.Empty<QuestionInfo>();
            }
        }

        public dynamic GetProductReviews(Int32 productId, Int32? pageIndex = null, Int32? pageSize = null)
        {
            pageIndex = pageIndex ?? 1;
            pageSize = pageSize ?? 20;

            var product = GetProductById(productId);
            if (product != null)
            {
                var reviews = product.Reviews.Where(r => r.IsPublished).OrderByDescending(r => r.CreateDate).Select(r => new
                {
                    CreateDate = r.CreateDate.ToString("F"),
                    Name = r.Customer.FullName(),
                    r.Rate,
                    r.Remark
                });
                return new
                {
                    Items = reviews.Skip(pageSize.Value * (pageIndex.Value - 1)).Take(pageSize.Value).AsEnumerable(),
                    Total = reviews.Count(),
                    PageSize = pageSize
                };
            }
            else
            {
                return new
                {
                    Items = Enumerable.Empty<ReviewInfo>(),
                    PageSize = pageSize.Value,
                    Total = 0
                };
            }

        }
    }
}
